import { Icon, Stroke, Style } from 'ol/style'
import { getUid } from 'ol/util'
import arrowRightImg from './images/arrowright.svg'
import { OlPoint ,OlFeature, OlLineString } from './type'
import { toColorRgba, fromLonLat, decoratePath } from './utils'

const defaultOptions = {
	mode: 'all', // 轨迹线模式
	path: [], // 点坐标数组
	zIndex: 2, // 覆盖物的叠加顺序
	showDir: true, // 是否显示白色方向箭头
	strokeOpacity: 0.9, //  线条透明度
	strokeWeight: 10, //  线条宽度
	strokeStyle: 'solid', // 轮廓线样式，实线: solid 虚线:dashed
	strokeDasharray: [], // 轮廓线间隙
	lineCap: 'butt', // 折线两端线帽的绘制样式，默认值为'butt'无头，其他可选值：'round'圆头、'square'方头
	lineJoin: 'round', // 折线拐点的绘制样式，默认值为'round'圆角，其他可选值：'round'圆角、'bevel'斜角
	isOutline: false, // 线条是否带描边，默认false
	borderWeight: 10, // 描边的宽度，默认为1
	outlineColor: '#000000', // 线条描边颜色，此项仅在isOutline为true时有效，默认：#000000
	extData: null, // 自定义信息
	segmentLength: 2, // 分段最小路径长度
	units: 'meters' // 分段最小路径单位
}

class WPolyline {
	constructor(data) {
		const { map, ...otherOptions } = data
		let originPath = otherOptions.path // 原始路径
		// history => 单历史轨迹, real => 实时轨迹, all => 双历史轨迹
		this.mode = otherOptions.mode
		// 只有历史双轨迹才需要计算虚拟轨迹点（虚拟轨迹点计算复杂度高，耗费时间）
		// webwork文件是自定义开发的，只有work文件内使用的turf库是固定的
		const workJs = window.browserData.envMODE === 'dev' ? '/map/work.js' : 'http://1.95.157.217/static/wmap-work/work.js'
		// 新建 Worker 实例
		const worker = new Worker(workJs);
		let flatArr = []
		if (this.mode === 'all') {
			// 向 Worker 发送消息
			worker.postMessage({
				type: 'decoratePath',
				value: {
					path: otherOptions.path,
					segmentLength: otherOptions.segmentLength,
					units: otherOptions.units
				}
			});
			// 接收来自 Worker 的消息并处理
			worker.onmessage = e => {
				this.options.path = e.data.value
				console.log('历史轨迹虚拟点计算完成, 目前虚拟轨迹段数目: ', e.data.value.length);
				const VectorLayerSource = map.getVectorLayer().getSource()
				const isExist = VectorLayerSource.hasFeature(this.olTarget)
				if (isExist) {
					VectorLayerSource.removeFeature(this.olTarget)
				}
				this.olTarget = createPolyline(this.options, map, this.mode)
				this.id = getUid(this.olTarget)
				this.map.add(this)
			};
		} else {
			flatArr = []
		}
		const options = Object.assign({}, defaultOptions, {
			...otherOptions,
			path: flatArr, // 对传入的路径数据进行去重
			originPath // 原始路径数据
		})
		const olTarget = this.mode === 'all' || this.mode === 'history' ? createPolyline(options, map, this.mode) : null

		this.WTYPE = 'POLYLINE'

		this.options = options

		this.olTarget = olTarget // 历史轨迹线

		this.activeTarget = null // 实时轨迹线

		this.id = this.olTarget && getUid(this.olTarget)

		this.map = map
		// 历史轨迹线样式集合
		this.historyPolylineStyle = []
		
		this.getVirtuaPath = () => this.options.path
		/**
		 * 設置正在跑的路徑坐标集合
		 * @param {*} coordinates
		 * @param {*} time
		 */
		this.setPath = coordinates => {
			// 历史双轨迹
			if (this.mode === 'all') {
				if (!this.activeTarget) {
					const geoPolyline = new OlLineString([])
					this.activeTarget = new OlFeature({
						geometry: geoPolyline
					})
					let option = {
						...this.options,
						strokeColor: options.activeStrokeColor
					}
					this.activeTarget.setStyle(createPolylineStyle(option))
					this.map.getVectorLayer().getSource().addFeature(this.activeTarget)
				} else {
					if (coordinates.length) {
						const geometry = this.activeTarget.getGeometry()
						let coorLists = geometry.getCoordinates()
						coorLists = coordinates.map(item => fromLonLat(item))
						geometry.setCoordinates(coorLists)
					} else {
						this.clearRealPath()
					}
				}
				// 实时轨迹
			} else if (this.mode === 'real') {
				if (!this.activeTarget) {
					const tmpPoint = fromLonLat(coordinates)
					let originPath = []
					originPath.push(coordinates) // 原始路径数据
					const geoPolyline = new OlLineString([tmpPoint])
					this.activeTarget = new OlFeature({
						geometry: geoPolyline,
						extData: this.options.extData,
						name: 'realTrack',
						options: {
							...this.options,
							originPath: originPath
						}
					})
					let option = {
						...this.options,
						strokeColor: options.activeStrokeColor
					}
					this.activeTarget.setStyle(createPolylineStyle(option))
					this.map.getVectorLayer().getSource().addFeature(this.activeTarget)
				} else {
					if (Array.isArray(coordinates[0]) && coordinates.length > 1) {
						const geometry = this.activeTarget.getGeometry()
						let coorLists = geometry.getCoordinates()
						coorLists = coordinates.map(item => fromLonLat(item))
						geometry.setCoordinates(coorLists)
					} else {
						let olPath = this.activeTarget.get('options')
						olPath.originPath.push(coordinates)
						const tmpPoint = fromLonLat(coordinates)
						this.activeTarget.getGeometry().appendCoordinate(tmpPoint)
						this.activeTarget.set('options', olPath)
					}
				}
			// 历史单轨迹 可清除轨迹，但是不可赋值，因为这是单轨迹的特性
			} else {
				if (!coordinates.length) {
					this.clearHistoryPath()
				}
			}
		}
		/**
		 * 根据行驶进度更新驶过轨迹线位置
		 */
		this.updatePassedPath = distance => {
			if (this.activeTarget) {
				const path = this.getVirtuaPath()
				const passedPath = path.slice(0, distance + 1)
				this.setPath(passedPath)
			}
		}
		/**
		 * 清除历史轨迹路径
		 */
		this.clearHistoryPath = () => {
			this.olTarget?.getGeometry().setCoordinates([])
		}
		/**
		 * 清除实时轨迹路径
		 */
		this.clearRealPath = () => {
			this.activeTarget?.getGeometry().setCoordinates([])
		}
		/**
		 * 获取历史轨迹路径
		 */
		this.getHistoryPath = () => {
			return this.olTarget?.get('options').path
		}
		/**
		 * 获取实时轨迹路径
		 * @returns 
		 */
		this.getRealPath = () => {
			return this.activeTarget?.getGeometry().getCoordinates()
		}
		/**
		 * 获取options属性值
		 * @param {*} type 属性
		 * @returns
		 */
		this.get = type => {
			return this.options?.[type] ?? false
		}
		/**
		 * 设置options属性值
		 * @param {*} value 属性
		 * @param {*} value 值
		 * @returns
		 */
		this.set = (type, value) => {
			if (this.options[type]) {
				this.options[type] = value
			}
		}
		/**
		 * 隐藏/显示 历史轨迹线(只适用于有历史轨迹线模式)
		 * @param {*} type 
		 */
		this.setVisible = (type) => {
			if (this.mode === 'real') return;
			// 显示轨迹线
			if (type) {
				this.olTarget.setStyle(feature => {
					return this.historyPolylineStyle
				})
			// 隐藏轨迹线
			} else {
				this.historyPolylineStyle = this.olTarget.getStyle()(this.olTarget)
				this.olTarget.setStyle(feature => {
					return null
				})
			}
		}
		// 初始化添加到 map 默认图层上
		if (this.map && this.map.WTYPE === 'MAP') {
			this.mode !== 'real' && this.map.add(this)
		}
		return this
	}
}
/**
 * 初始化历史轨迹完整样式
 * @param {*} options
 * @param {*} map
 * @returns
 */

function createPolyline(options, map, mode) {
	let newPath = []
  if (mode === 'all') {
    newPath = options.path?.map(coordinates => fromLonLat(coordinates)) ?? []
  } else {
    newPath = options.originPath.map(coordinates => fromLonLat(coordinates))
  }
	const geoPolyline = new OlLineString(newPath)
	const featurePolyline = new OlFeature({
		geometry: geoPolyline,
		extData: options.extData,
		linePath: options.originPath,
		options
	})
	featurePolyline.setStyle(feature => {
		const options = feature.get('options')
		const styles = createPolylineStyle(options)
		//箭头样式
		options.showDir && styles.push(...createArrowPolylineStyle(newPath, options.strokeWeight, map))
		return styles
	})
	return featurePolyline
}

/**
 * Polyline 箭头样式
 * 用于每次渲染集合体的时候，OL 均会调用此函数以获得自定义样式
 * @param path
 * @param map
 * @returns {undefined[]}
 */
const createArrowPolylineStyle = function (coords, lineWidth, map) {
	// 内部箭头间隔距离（像素）
	const step = 40
	let distance = step / 2 //首个点放置在距离起点1/2间隔的位置
	let styles = []
	// 获取起始像素坐标
	let pixStart = map.getPixelFromCoordinate(coords[0])
	let pixEnd
	for (let i = 1; i < coords.length; i++) {
		let coord, coordPix, style
		// 获取当前第一个箭头位置
		pixEnd = map.getPixelFromCoordinate(coords[i])
		let distanceStart2end = Math.sqrt(Math.pow(pixStart[0] - pixEnd[0], 2) + Math.pow(pixStart[1] - pixEnd[1], 2)) //计算收尾在屏幕上的距离
		if (distanceStart2end > distance) {
			//距离大于间隔
			//计算距离开始点位的像素值
			coordPix = [
				(distance * (pixEnd[0] - pixStart[0])) / distanceStart2end + pixStart[0],
				(distance * (pixEnd[1] - pixStart[1])) / distanceStart2end + pixStart[1]
			]
			//计算经纬度
			coord = map.getCoordinateFromPixel(coordPix)
			style = new Style({
				geometry: new OlPoint(coord),
				image: new Icon({
					src: arrowRightImg,
					rotateWithView: true,
					rotation: Math.atan2(pixEnd[1] - pixStart[1], pixEnd[0] - pixStart[0]),
					scale: lineWidth / 12
				})
			})
			//下次循环开始点为当前点
			pixStart = coordPix
			distance = step
			i--
		} else if (distanceStart2end == distance) {
			//距离等于间隔
			style = new Style({
				geometry: new OlPoint(coords[i]),
				image: new Icon({
					src: arrowRightImg,
					rotateWithView: true,
					rotation: Math.atan2(pixEnd[1] - pixStart[1], pixEnd[0] - pixStart[0]),
					scale: lineWidth / 12
				})
			})
			pixStart = pixEnd
			distance = step
		} else {
			//距离小于间隔
			distance = distance - distanceStart2end
			pixStart = pixEnd
		}
		style && styles.push(style)
	}
	return styles
}
/**
 * Polyline 线条默认样式
 * 用于每次渲染集合体的时候，OL 均会调用此函数以获得自定义样式
 * @param options
 * @param toColorRgba
 * @returns {undefined[]}
 */
const createPolylineStyle = function (options) {
	let lineDash = options.strokeDasharray
	//处理虚线
	if (options.strokeStyle === 'dashed') {
		lineDash = options.strokeDasharray.length ? options.strokeDasharray : [options.strokeWeight * 2, options.strokeWeight]
	} else {
		lineDash = [0, 0]
	}
	const style = new Style({
		stroke: new Stroke({
			zIndex: options.zIndex,
			color: toColorRgba(options.strokeColor, options.strokeOpacity),
			width: options.strokeWeight,
			lineCap: options.lineCap, // 折线两端线帽的绘制样式，默认值为'butt'无头，其他可选值：'round'圆头、'square'方头
			lineJoin: options.lineJoin, // 折线拐点的绘制样式，默认值为'miter'尖角，其他可选值：'round'圆角、'bevel'斜角
			lineDash, // 线间隔模式 这个变化与分辨率有关 默认为undefined Internet Explorer 10和更低版本不支持
			lineDashOffset: 0, // 线段间隔偏移 默认0
			miterLimit: 0 // 默认10
		})
	})
	const styleClone = style.clone()
	styleClone.getStroke().setColor(toColorRgba(options.outlineColor))
	styleClone.getStroke().setWidth(options.strokeWeight + options.borderWeight)
	return options.isOutline ? [styleClone, style] : [style]
}
export default WPolyline
